#include <stdio.h>
#include "oled.h"
#include "oled_fonts.h"
#include "dataProcess.h"
#include "cmsis_os2.h"
#include <stdlib.h>
#include <time.h>
#include "DHT11_driver.h"

// 定义X轴刻度数组和温度数据数组
// xTicks数组存储X轴上刻度对应的位置
static const uint8_t xTicks[18] = {4, 9, 15, 21, 27, 33, 39, 45, 51, 57, 62, 68, 74, 80, 86, 92, 100, 106};
// temps数组用于存储温度数据
static tempData temps[18] = {0};
// tempIndex用于记录当前温度数据的索引
static long tempIndex = 0;
// humis数组用于存储湿度数据
static humiData humis[18] = {0};
// humiIndex用于记录当前湿度数据的索引
static long humiIndex = 0;

// 绘制温度坐标轴
void drawTempAxis(void) {
    // 清空屏幕，为绘制坐标轴做准备
    oledClear();

    // 绘制X轴（时间轴）
    // 从起始点(AXIS_ORIGIN_X, AXIS_ORIGIN_Y)到终点(AXIS_ORIGIN_X + AXIS_LENGTH_X, AXIS_ORIGIN_Y)绘制一条白色的线
    drawLine(AXIS_ORIGIN_X, AXIS_ORIGIN_Y, AXIS_ORIGIN_X + AXIS_LENGTH_X, AXIS_ORIGIN_Y, WHITE);

    // 绘制Y轴（温度轴）
    // 从起始点(AXIS_ORIGIN_X, AXIS_ORIGIN_Y)到终点(AXIS_ORIGIN_X, AXIS_ORIGIN_Y - AXIS_LENGTH_Y)绘制一条白色的线
    drawLine(AXIS_ORIGIN_X, AXIS_ORIGIN_Y, AXIS_ORIGIN_X, AXIS_ORIGIN_Y - AXIS_LENGTH_Y, WHITE);

    // 绘制X轴刻度（时间）
    // 每隔20个单位绘制一个刻度，共绘制7个刻度（0, 20, 40, 60, 80, 100, 120）
    for (int i = 0; i <= 120; i += 20) {
        // 计算刻度对应的X坐标
        int x = AXIS_ORIGIN_X + (i * AXIS_LENGTH_X) / 120;
        // 绘制刻度线，从X坐标位置向下绘制长度为TICK_LENGTH的白色线
        drawLine(x, AXIS_ORIGIN_Y, x, AXIS_ORIGIN_Y + TICK_LENGTH, WHITE); 
        // 打印X坐标，用于调试
        printf("x: %d\n", x);
    }

    // 绘制Y轴刻度（温度）
    // 每隔10个单位绘制一个刻度，共绘制6个刻度（0, 10, 20, 30, 40, 50）
    for (int i = 0; i <= 50; i += 10) {
        // 计算刻度对应的Y坐标
        int y = AXIS_ORIGIN_Y - (i * AXIS_LENGTH_Y) / 50;
        // 绘制刻度线，从Y坐标位置向左绘制长度为TICK_LENGTH的白色线
        drawLine(AXIS_ORIGIN_X - TICK_LENGTH, y, AXIS_ORIGIN_X, y, WHITE); 
        // 打印Y坐标，用于调试
        printf("y: %d\n", y);
    }

    // 绘制X轴标签（Time）
    // 在屏幕右下角绘制字符串"Time"
    drawString(OLED_WIDTH - ASCII_WIDTH * 4 - 1, AXIS_ORIGIN_Y - ASCII_HEIGHT - 2, "Time");

    // 绘制Y轴标签（Temp）
    // 在Y轴起始位置上方绘制字符串"Temp"
    drawString(AXIS_ORIGIN_X, 1, "Temp");
}

// 温度到刻度地址的计算函数
tempData tempScale(double temp) {
    // 温度范围：50°C 到 0°C
    // 刻度地址范围：10 到 60
    // 根据温度值计算对应的刻度地址
    uint8_t scale = 10 + (tempMax*1.1 - temp)*AXIS_LENGTH_Y/(tempMax*1.1-tempMin*0.9) ;
    // 创建一个tempData结构体，存储温度值、索引、X坐标和刻度地址
    tempData data = {temp, tempIndex % 18, xTicks[tempIndex % 18], scale};
    // 索引加1
    tempIndex++;
    return data;
}

// 绘制温度数据
void drawTemp(double Temp) {
    // 检查温度值是否超出范围
    if (Temp > TEMP_MAX ) {
        // 若超出范围，打印错误信息
        printf("Temperature out of range\n");
    }
    // 调用tempScale函数，初始化温度数据
    tempData data = tempScale(Temp);
    // 将温度数据存储到temps数组中
    temps[data.index % 18] = data;
    // 每隔3个数据点绘制一个点
    if (data.index % 3 == 1) {
        // 在对应的X、Y坐标位置绘制一个白色的点
        drawPoint(data.x, data.y, WHITE);
    }
    // 将温度值转换为字符串
    char tempStr[5];
    sprintf(tempStr, "%.1f", Temp);
    // 若不是第一个数据点，绘制连接上一个数据点和当前数据点的线
    if (data.index != 0) {
        drawLine(temps[(data.index - 1) % 18].x, temps[(data.index - 1) % 18].y, data.x, data.y, WHITE);
    }    
    // 根据索引和flag的值，在数据点上方或下方绘制温度值字符串
    if(data.index % 3 == 1&&flag%2==0){
        drawString(data.x, data.y - 12, tempStr);
    }else if(data.index % 3 == 1&&flag%2==1){
        drawString(data.x, data.y + 4, tempStr);
    }
    // flag加1
    flag++; 
}

// 绘制湿度坐标轴
void drawHumiAxis(void) {
    // 清空屏幕，为绘制坐标轴做准备
    oledClear();

    // 绘制X轴（时间轴）
    // 从起始点(AXIS_ORIGIN_X, AXIS_ORIGIN_Y)到终点(AXIS_ORIGIN_X + AXIS_LENGTH_X, AXIS_ORIGIN_Y)绘制一条白色的线
    drawLine(AXIS_ORIGIN_X, AXIS_ORIGIN_Y, AXIS_ORIGIN_X + AXIS_LENGTH_X, AXIS_ORIGIN_Y, WHITE);

    // 绘制Y轴（湿度轴）
    // 从起始点(AXIS_ORIGIN_X, AXIS_ORIGIN_Y)到终点(AXIS_ORIGIN_X, AXIS_ORIGIN_Y - AXIS_LENGTH_Y)绘制一条白色的线
    drawLine(AXIS_ORIGIN_X, AXIS_ORIGIN_Y, AXIS_ORIGIN_X, AXIS_ORIGIN_Y - AXIS_LENGTH_Y, WHITE);

    // 绘制X轴刻度（时间）
    // 每隔20个单位绘制一个刻度，共绘制7个刻度（0, 20, 40, 60, 80, 100, 120）
    for (int i = 0; i <= 120; i += 20) {
        // 计算刻度对应的X坐标
        int x = AXIS_ORIGIN_X + (i * AXIS_LENGTH_X) / 120;
        // 绘制刻度线，从X坐标位置向下绘制长度为TICK_LENGTH的白色线
        drawLine(x, AXIS_ORIGIN_Y, x, AXIS_ORIGIN_Y + TICK_LENGTH, WHITE); 
        // 打印X坐标，用于调试
        printf("x: %d\n", x);
    }

    // 绘制Y轴刻度（湿度）
    // 每隔10个单位绘制一个刻度，共绘制7个刻度（0, 10, 20, 30, 40, 50, 60）
    for (int i = 0; i <= 60; i += 10) {
        // 计算刻度对应的Y坐标
        int y = AXIS_ORIGIN_Y - (i * AXIS_LENGTH_Y) / 60;
        // 绘制刻度线，从Y坐标位置向左绘制长度为TICK_LENGTH的白色线
        drawLine(AXIS_ORIGIN_X - TICK_LENGTH, y, AXIS_ORIGIN_X, y, WHITE); 
        // 打印Y坐标，用于调试
        printf("y: %d\n", y);
    }

    // 绘制X轴标签（Time）
    // 在屏幕右下角绘制字符串"Time"
    drawString(OLED_WIDTH - ASCII_WIDTH * 4 - 1, AXIS_ORIGIN_Y - ASCII_HEIGHT - 2, "Time");

    // 绘制Y轴标签（Humi）
    // 在Y轴起始位置上方绘制字符串"Humi"
    drawString(AXIS_ORIGIN_X, 1, "Humi");
}

// 湿度到刻度地址的计算函数
humiData humiScale(double humi) {
    // 湿度范围：90%RH 到 30%RH
    // 刻度地址范围：10 到 60
    // 根据湿度值计算对应的刻度地址
    uint8_t scale = 10 + (humiMax*1.2 - humi) *AXIS_LENGTH_Y/(humiMax*1.2-humiMin*0.8);
    // 创建一个humiData结构体，存储湿度值、索引、X坐标和刻度地址
    humiData data = {humi, humiIndex % 18, xTicks[humiIndex % 18], scale};
    // 索引加1
    humiIndex++;
    return data;
}

// 绘制湿度数据
void drawHumi(double Humi) {
    // 检查湿度值是否超出范围
    if (Humi > HUMI_MAX || Humi < HUMI_MIN) {
        // 若超出范围，打印错误信息
        printf("Humidity out of range\n");
    }
    // 调用humiScale函数，初始化湿度数据
    humiData data = humiScale(Humi);
    // 将湿度数据存储到humis数组中
    humis[data.index % 18] = data;
    // 每隔3个数据点绘制一个点
    if (data.index % 3 == 1) {
        // 在对应的X、Y坐标位置绘制一个白色的点
        drawPoint(data.x, data.y, WHITE);
    }
    // 将湿度值转换为字符串
    char humiStr[5];
    sprintf(humiStr, "%.1f", Humi);
    // 若不是第一个数据点，绘制连接上一个数据点和当前数据点的线
    if (data.index != 0) {
        drawLine(humis[(data.index - 1) % 18].x, humis[(data.index - 1) % 18].y, data.x, data.y, WHITE);
    }
    // 根据索引和flag的值，在数据点上方或下方绘制湿度值字符串
    if(data.index % 3 == 1&&flag%2==0){
        drawString(data.x, data.y - 12, humiStr);
    }else if(data.index % 3 == 1&&flag%2==1){
        drawString(data.x, data.y + 4, humiStr);
    }
    // flag加1
    flag++;
}

// 初始化温度数据
void tempInit(double *temperatures,double *humidities) {
    // 调用drawTempAxis函数，绘制温度坐标轴
    drawTempAxis();
    // 更新OLED屏幕显示
    oledUpdate();
    // 循环18次，获取18个温度和湿度数据
    for (int i = 0; i < 18; i++) {
        // 延时200ms
        osDelay(200);
        // 调用DHT11_Temp函数，获取当前温度值
        double temp = DHT11_Temp();
        // 调用DHT11_Humidity函数，获取当前湿度值
        double humi = DHT11_Humidity();
        // 打印温度值，用于调试
        printf("temp: %.1f\n", temp);
        // 调用drawTemp函数，绘制温度数据
        drawTemp(temp);
        // 将温度值存储到temperatures数组中
        temperatures[i] = temp;
        // 将湿度值存储到humidities数组中
        humidities[i] = humi;
        // 更新OLED屏幕显示
        oledUpdate();
    }
}

// 初始化湿度数据
void humiInit(int *humidities) {
    // 调用drawHumiAxis函数，绘制湿度坐标轴
    drawHumiAxis();
    // 更新OLED屏幕显示
    oledUpdate();
    // 循环18次，获取18个湿度数据
    for (int i = 0; i < 18; i++) {
        // 延时200ms
        osDelay(200);
        // 生成一个0到90之间的随机整数作为湿度值
        int humi = rand() % 91;
        // 打印湿度值，用于调试
        printf("humi: %.1f\n", humi);
        // 调用drawHumi函数，绘制湿度数据
        drawHumi(humi);
        // 将湿度值存储到humidities数组中
        humidities[i] = humi;
        // 更新OLED屏幕显示
        oledUpdate();
    }
}